package com.zzw.junit5demo;

import com.zzw.junit5demo.extension.TimingExtension;
import io.qameta.allure.*;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.condition.EnabledIf;
import org.junit.jupiter.api.condition.EnabledOnOs;
import org.junit.jupiter.api.condition.OS;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.time.Duration;
import java.util.Objects;
import java.util.stream.Stream;

import static org.junit.jupiter.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

/**
 * @author zzw
 * @version 1.0
 * @title ExampleDemo
 * @description <Junit5测试例子>
 * @datetime 2023-02-08 20:47
 */

@DisplayNameGeneration(DisplayNameGenerator.Simple.class)
@DisplayName("计算器测试用例")
@Feature("模块名称")
// @Execution(ExecutionMode.CONCURRENT)
@ExtendWith(TimingExtension.class)
// @TestMethodOrder(MethodOrderer.DisplayName.class)
public class ExampleDemo {

    private static final Logger logger = LoggerFactory.getLogger(ExampleDemo.class);

    @BeforeAll
    public static void beforeClass(){
        logger.info("beforeClass 执行");
    }

    @AfterAll
    public static void afterClass(){
        logger.info("afterClass 执行");
    }

    @BeforeEach
    @DisplayName("初始化标识ID")
    public void setUp() {
        logger.info("初始化标识ID");
    }

    @AfterEach
    @DisplayName("销毁标识ID")
    public void tearDown() {
        logger.info("销毁标识ID");
    }


    @Test
    @DisplayName("测试用例00")
    void testCase000(){
        logger.info("测试用例00");
        assumeTrue(1 == 1);
    }

    @DisplayName("测试用例01")
    // @RepeatedTest(2)
    @RepeatedTest(value = 2, name = "{displayName}-{currentRepetition}/{totalRepetitions}")
    void testCase001(){
        logger.info("测试用例01, 重复测试");
    }

    @ParameterizedTest
    @ValueSource(strings = { "Hello", "JUnit" })
    @DisplayName("测试用例02")
    void testCase002(String value) {
        logger.info("带参数的测试用例 {}", value);
        loginWith(value);
        logoutWith();
        try {
            String filePath = Objects.requireNonNull(getClass().getClassLoader().getResource("oneplace.jpeg")).getFile();
            FileInputStream fileInputStream = new FileInputStream(filePath);
            Allure.addAttachment("图片附件", fileInputStream);
        }catch (Exception e){
            logger.error("添加附件异常", e);
        }

        // byte[] a = new byte[] {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13};
        // saveScreenshot(a);
        assertEquals("Hello", value);
        assertTrue(value.length() > 0);
    }

    @Attachment(value = "用例2测试截图")
    public byte[] saveScreenshot(byte[] screenShot) {
        return screenShot;
    }

    @Step("登录。用户名: {username} 密码：****")
    public void loginWith(String username){
        logger.info("测试用例03 登陆步骤 === {}", username);
    }

    @Step("登出")
    public void logoutWith(){
        logger.info("测试用例03 登出步骤");
    }

    @Test
    @Disabled
    @DisplayName("测试用例03")
    void testCase003(){
        logger.info("测试用例03 禁用忽略");

    }

    @Test
    @EnabledOnOs(OS.MAC)
    @DisplayName("测试用例04")
    @Description("测试用例04 在mac系统才能运行")
    void testCase004(){
        logger.info("测试用例04 在mac系统运行");
        assertTimeout(Duration.ofSeconds(3), () -> Thread.sleep(3));
        // 分组断言
        assertAll("all", () -> {
            assertEquals(2, 1+1);
            assertEquals(2, 1+2);
        });
    }

    boolean costumerCondition(){
        return false;
    }

    @Test
    // @EnabledOnOs({OS.WINDOWS, OS.LINUX})
    // @EnabledIfSystemProperty(named = "java.vm.name", matches=".*HotSpot.*")
    @EnabledIf("costumerCondition")
    // @EnabledForJreRange(min =JRE.JAVA_8, max = JRE.JAVA_11)
    @DisplayName("测试用例05")
    void testCase005(){
        logger.info("测试用例05 在win系统运行");
        assertEquals(2, Math.addExact(1, 1));
    }

    @Test
    @Tag("zzw")
    @DisplayName("测试用例06")
    void testCase006(TestInfo info){
        logger.info("testCase006。 tag 标签={}", info.getTags());
        Exception exception = assertThrows(IllegalArgumentException.class, this::willThrows);
        assertEquals("参数异常", exception.getMessage());
    }

    private void willThrows(){
        try{
            Thread.sleep(1);
        }catch (Exception e){
            throw new IllegalArgumentException("参数异常");
        }
    }


    @DisplayName("测试用例07")
    @ParameterizedTest
    @CsvFileSource(resources = "/data.csv", delimiterString = "｜")
    @CsvSource({"测试1,19", "开发1,20", "产品1,10"})
    void testCase007(String name, int age){
        logger.info("测试用例07。 参数化 name={}, age={}", name, age);
    }


    @DisplayName("测试用例08")
    @ParameterizedTest
    @MethodSource("stringStream")
    @NullAndEmptySource
    void testCase008(String agreement){
        logger.info("测试用例08。 参数化 agreement={}", agreement);
    }

    static Stream<String> stringStream(){
        return Stream.of("A", "B", "C", "D");
    }

    @DisplayName("测试用例09")
    @ParameterizedTest
    @MethodSource("argumentsStream")
    @Timeout(1)
    void testCase009(int id, String name, String position){
        logger.info("测试用例09。 多参数化 id={} name={} position={}", id, name, position);
    }

    static Stream<Arguments> argumentsStream(){
        return Stream.of(
                Arguments.arguments(1, "张三", "警察"),
                Arguments.arguments(2, "李四", "医生"),
                Arguments.arguments("", "李四", "医生")
        );
    }


    @NullSource
    @EmptySource
    @ParameterizedTest
    @EnumSource()
    @ValueSource(strings = { " ", "   ", "\t", "\n" })
    @DisplayName("测试用例11")
    void nullEmptyAndBlankStrings(String text) {
        assertTrue(text == null || text.trim().isEmpty());
    }

    @DisplayName("测试用例10")
    @Nested
    class Manager{
        @Nested
        @DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
        class AdminManager{
            @Test
            void queryAll(){
                logger.info("测试用例10。查询所有用户");
            }
        }
        @Nested
        class UserManager{
            @Test
            void querySelf(){
                logger.info("测试用例10。查询自己");
            }
        }
    }

}
